﻿#include <xy/ais/arrow.h>

namespace xy
{

namespace ais
{

using namespace xy::geom;

arrow::arrow(std::shared_ptr<vec3> origin, std::shared_ptr<vec3> vector) : m_origin(origin), m_vector(vector)
{
}

std::shared_ptr<vec3> arrow::vector() const
{
    return m_vector;
}

std::shared_ptr<vec3> arrow::origin() const
{
    return m_origin;
}

bool arrow::collision(msg_mouse *msg)
{
    // 获得两个屏幕点和鼠标位置（跳过开头和尾部的一段距离，以避免与所在点位置过近）
    vec3f Q1 = msg->screenMapping(convert<float>(*m_origin + *m_vector * 0.1));
    vec3f Q2 = msg->screenMapping(convert<float>(*m_origin + *m_vector * 0.9));
    vec2f q1(Q1.x(), Q1.y());
    vec2f q2(Q2.x(), Q2.y());
    vec2f p = msg->movePos;

    // 计算投影长度
    vec2f dir = q2 - q1;
    float len = dir.modulus();

    // 排除向量垂直于屏幕的情况
    if (len < std::numeric_limits<float>::epsilon())
        return false;

    float d = dot(p - q1, dir / len);
    float t = d / (q2 - q1).modulus();

    // 如果在范围内，直接将深度设为 0
    if (t > 0 && t < 1 && (q1 * (1 - t) + q2 * t).distance(p) < 2)
    {
        msg->depth = 0;
        msg->captured = this;
        return true;
    }
    return false;
}

void arrow::visit(msg_init *msg)
{
    // 利用工厂创建渲染器
    if (msg->factory)
        m_renderer.reset(msg->factory->create_product("arrow"));
}

void arrow::visit(msg_move *msg)
{
    vec3 n = convert<double>(msg->dir);
    vec3 p = convert<double>(msg->pos);
    vec3 tar = p + n * dot(n, *m_origin - p);
    vec3 v = m_vector->normalized();
    *m_origin = *m_origin + v * dot(v, tar - *m_origin);

    // 调用父类方法更新
    object::visit(msg);
}

} // namespace ais

} // namespace xy
